package com.ficus.road.maintain.authority.service;

import com.ficus.road.maintain.authority.dao.RoleDao;
import com.ficus.road.maintain.authority.dao.UserDao;
import com.ficus.road.maintain.authority.dto.RoleDTO;
import com.ficus.road.maintain.authority.dto.UserDTO;
import com.ficus.road.maintain.authority.vo.RoleVO;
import com.ficus.road.maintain.core.exception.CommonException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xiawen yang
 * @date 2021/8/25 下午7:23
 */
@Service
@Slf4j
public class RoleService {

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private UserDao userDao;

    public List<RoleVO> queryAllRoles() {
        List<RoleVO> roleVOs = new ArrayList<>();
        List<RoleDTO> roles = roleDao.findAll();
        roles.stream().forEach(
                role -> {
                    List<UserDTO> userList = userDao.findByQuery(new Query(Criteria.where("role_id_list").is(role.getId())));
                    RoleVO roleVO = RoleVO.builder().roleId(role.getId()).roleName(role.getRoleName()).createdBy(role.getCreateBy())
                            .createTime(role.getCreateTime()).frontConfigs(role.getFrontConfigs())
                            .userInfos(userList).build();
                    roleVOs.add(roleVO);
                }
        );
        return roleVOs;
    }

    public String updateRoleAuthorityConfig(String roleId, RoleVO roleVO) {
        RoleDTO fetch = roleDao.fetch(roleId);
        if (Objects.isNull(fetch)) {
            log.error("updateRole fail, roleId not found! roleId: {}", roleId);
            throw new CommonException("updateRole fail, roleId not found! roleId: " + roleId, 400);
        }
        fetch.setFrontConfigs(roleVO.getFrontConfigs());
        fetch.setUpdateTime(new Date().getTime() / 1000);
        roleDao.saveOrUpdate(fetch);
        return roleId;
    }

    public String deleteRelation(String roleId, String userId) {
        UserDTO fetch = userDao.fetch(userId);
        if (Objects.isNull(fetch)) {
            log.error("deleteRelation fail, userId:{} is not exist", userId);
            throw new CommonException("updateUser fail, userId" + userId + " is not exist", 400);
        }
        Set<String> roleIdList = fetch.getRoleIdList();
        roleIdList.remove(roleId);
        fetch.setUpdateTime(new Date().getTime() / 1000);
        userDao.saveOrUpdate(fetch);
        return roleId;
    }

    public String createRelation(String roleId, List<String> userIdList) {
        List<UserDTO> userDTOS = userDao.findByQuery(new Query(Criteria.where("_id").in(userIdList)));
        if (Objects.isNull(userDTOS)) {
            log.error("createRelation fail, userIdList is not exist");
            throw new CommonException("createRelation fail, userIdList is not exist", 400);
        }
        userDTOS.stream().forEach(
                user -> {
                    Set<String> roleIdList = user.getRoleIdList();
                    roleIdList.add(roleId);
                    user.setUpdateTime(new Date().getTime() / 1000);
                    user.setRoleIdList(roleIdList);
                    userDao.saveOrUpdate(user);
                }
        );
        return roleId;
    }

    public List<RoleDTO> queryRolesById(Set<String> roleIds) {
        List<RoleDTO> roleDTOS = new ArrayList<>();
        roleIds.forEach(roleId -> {
            RoleDTO fetch = roleDao.fetch(roleId);
            roleDTOS.add(fetch);
        });
        return roleDTOS;
    }

    public List<GrantedAuthority> mapToGrantedAuthorities(UserDTO user) {
        Set<String> roleIdList = user.getRoleIdList();
        Set<String> permissions = new HashSet<>();
        List<RoleDTO> roleDTOS = queryRolesById(roleIdList);
        for (int i = 0; i < roleDTOS.size(); i++) {
            RoleDTO role = roleDTOS.get(i);
            if (role.getRoleName().equals("管理员")) {
                permissions.add("ADMIN");
                return permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
            }
            permissions.addAll(role.getFrontConfigs());
        }
        return permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
    }

    public void initRole(){
        RoleDTO roleDTO = new RoleDTO();
        roleDTO.setRoleName("管理员");
        roleDTO.setFrontConfigs(Sets.newHashSet("INDEX", "DISTRICTION","ROAD_NETWORK","PATROL","ROAD_INDICATORS",
                "FPV","AUTHORITY","CAR","SMART", "EMERGENCY"));
        RoleDTO insert = roleDao.insert(roleDTO);

    }
}
